home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
DDJMAG
/
DDJ9203.ZIP
/
DRVMONIT.ZIP
/
LOGCMD.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-11-29
|
50KB
|
1,291 lines
;---------------------------------------------------------------
;logcmd - command processing for device driver monitor |
;--------------------------------------------------------------|
;Copyright 1990, 1992 ASMicro Co. |
;--------------------------------------------------------------|
; |
; 4/15/90 Rick Knoblaugh |
;--------------------------------------------------------------|
;include files |
;---------------------------------------------------------------
include logequ.inc
include logstruc.inc
code segment public 'CODE'
assume cs:code, ds:code, es:code
;--------------------------------------------------------------
;PUBLIC |
;--------------------------------------------------------------
public monitor_process
public drv_open
public drv_close
public drv_ioctl_in
public drv_ioctl_out
public drv_non_supt
public patch_flag
public old_user_int
public drv_state
public save_patch
public get_key
public req_header
public show_buffer
public record_cmd
public find_func
public find_sub_func
public config_dat
public cmd_table
public old_stack_ptr
public old_stack_seg
public logr_stack
public logr_sp
public prt_to_mem
;--------------------------------------------------------------
include logdat.inc ;data for driver monitor
;--------------------------------------------------------------
;The following perform processing depending on what call into
;monitored device driver is occurring.
;--------------------------------------------------------------
state_handlers dw process_nothing
dw process_strat
dw process_int
dw process_ret
out_table dw prt_to_null
dw prt_to_printer
dw prt_to_screen
dw prt_to_mem
drv_non_supt proc near
mov ax, ERR_UNKNOWN
ret
drv_non_supt endp
drv_open proc near
drv_close proc near
mov ax, OK_STATUS
ret
drv_close endp
drv_open endp
;--------------------------------------------------------------
;drv_ioctl_out - receive from caller a far ptr to a user |
; buffer area in which to log data, and a dword|
; value containing the size in bytes of this |
; data area. |
;--------------------------------------------------------------
drv_ioctl_out proc near
les di, req_header ;get ptr to request header
mov ax, ERR_GENFAIL ;default to error
;is this the number of bytes we are expecting?
cmp es:[di].ioctl_count, size ioctl_out_data
jne short drv_ioctl_o999 ;if not, error
drv_ioctl_o100:
les di, es:[di].ioctl_buf_ptr ;get ptr to DTA
push ds
lds bx, es:[di].user_buf_ptr ;get user's buffer ptr
mov cs:user_data_ptr.d_offset, bx ;save it
mov cs:user_data_ptr.d_segment, ds
lds bx, es:[di].user_buf_size ;get size of buffer
mov cs:user_data_size.d_offset, bx ;save it
mov cs:user_data_size.d_segment, ds
pop ds
mov ax, OK_STATUS
drv_ioctl_o999:
ret
drv_ioctl_out endp
;--------------------------------------------------------------
;drv_ioctl_in - pass back to caller, a far ptr to our count of|
; bytes written to user data area, offset of |
; our configuration info, and offset of our |
; command table info. |
; |
;--------------------------------------------------------------
drv_ioctl_in proc near
les di, req_header ;get ptr to request header
mov es:[di].ioctl_count, size ioctl_in_data ;pass count
les di, es:[di].ioctl_buf_ptr ;get ptr to DTA
mov ax, offset wrk_data_count ;pass back pointer to
;our buffer count
mov es:[di].drv_buf_count.d_offset, ax
mov es:[di].drv_buf_count.d_segment, cs
mov ax, offset config_dat
mov es:[di].drv_config_dat, ax
mov ax, offset cmd_table
mov es:[di].drv_cmd_tbl, ax
mov ax, OK_STATUS
ret
drv_ioctl_in endp
;--------------------------------------------------------------
;monitor_process |
;--------------------------------------------------------------
monitor_process proc far
cli
mov cs:old_stack_ptr, sp
mov cs:old_stack_seg, ss
mov sp, cs
mov ss, sp
mov sp, offset cs:logr_sp
sti
cld
push ds
push es
push ax
push bx
push cx
push dx
push di
push si
push cs ;get our ds
pop ds
mov di, drv_state
shl di, 1
;
;Proccess based on which area of driver being monitored generated the
;user software interrupt.
;
call word ptr [di + state_handlers]
pop si
pop di
pop dx
pop cx
pop bx
pop ax
pop es
pop ds
cli
mov sp, cs:old_stack_ptr
mov ss, cs:old_stack_seg
sti
iret
monitor_process endp
process_nothing proc near
ret
process_nothing endp
;--------------------------------------------------------------
;process_strat - store the es:bx ptr to the request header |
; coming into the driver being monitored. Also|
; patch in an int instruction at start of |
; driver's interrupt routine. Set next state |
; to indicate next int should come from driver |
; interrupt routine. |
;--------------------------------------------------------------
process_strat proc near
mov mdrv_req_ptr.d_offset, bx ;save ptr to req header
mov mdrv_req_ptr.d_segment, es
les bx, dword ptr old_stack_ptr
les di, dword ptr es:[bx].mdrv_off ;ptr to start of code
mov mdrv_strat_ptr.d_segment, es
;
;Determine if the int instruction that gave us control was patched into
;the driver being monitored or is part of the driver source code. This
;is to decide where to return: at the instruction (replaced with former
;object code), or after the int instruction.
;
cmp patch_flag, TRUE ;indicates that user patched
jne process_s100
sub di, 2 ;offset of int instruction
;
;When return occurs, control will pass back to code at int instruction
;which will be overlaid with the original code contents. Adjust the
;value on the stack.
push ds
lds bx, dword ptr old_stack_ptr ;get old ss and sp
mov [bx].mdrv_off, di
pop ds
mov ax, save_patch ;get the original 2 bytes of code
mov es:[di], ax ;put it back
process_s100:
mov mdrv_strat_ptr.d_offset, di
;
;Determine if address of interrupt routine for driver being monitored has
;been stored yet. If not, retrieve the address from the device driver
;header.
cmp mdrv_int_ptr.d_segment, NULL
jne process_s200
mov mdrv_int_ptr.d_segment, es ;seg of int routine
xor bx, bx ;offset header
mov ax, es:[bx].dev_int
mov mdrv_int_ptr.d_offset, ax ;offset of int routine
process_s200:
mov di, mdrv_int_ptr.d_offset
;
;Save first 2 bytes of code at the interrupt routine. Patch in the
;int instruction which will give us control.
call save_n_patch
mov drv_state, EXPECT_INT
cmp header_flag, TRUE ;printed log header already?
je process_s300
call prt_log_hdr ;print name, load address etc.
mov header_flag, TRUE
process_s300:
ret
process_strat endp
;--------------------------------------------------------------
;process_int |
;--------------------------------------------------------------
process_int proc near
;
;First, try to do a little checking to see if this is really the int routine.
;It's possible that the user of this program did not place the int which
;gives us control in the strategy routine. If things don't look like they
;should, simply return without attempting any monitoring.
;
les bx, dword ptr old_stack_ptr
les di, dword ptr es:[bx].mdrv_off ;&driver's int routine
mov ax, es
;is this the segment we
cmp ax, mdrv_int_ptr.d_segment ;are expecting?
jne process_i999
sub di, 2 ;back to "int" instruction
cmp di, mdrv_int_ptr.d_offset
jne process_i999
inc drv_req_num ;count requests to driver
;Replace the int instruction with original contents
;
call restor_instruc
;
;Fix value for the offset of where to return. Go back 2 bytes to location
;of int instruction.
les bx, dword ptr old_stack_ptr
mov es:[bx].mdrv_off, di ;put adjusted value back
les di, dword ptr es:[bx].mdrv_ret_off
;
;Save ptr to where driver being monitored will return after its int routine
;completes.
;
mov mdrv_ret_ptr.d_offset, di
mov mdrv_ret_ptr.d_segment, es
;
;Save code at that location and patch in int instruction
;
call save_n_patch
mov drv_state, EXPECT_USE_RET
cmp config_dat.show_cmd_blk, OUTPUT ;show only on return?
je process_i999
mov ax, drv_req_num ;exceeded number to log?
cmp ax, config_dat.max_to_log
ja process_i999 ;if yes, don't log any more
;
;Determine if the number of requests so far has reached the request number
;where the user wishes to start logging.
;
cmp ax, config_dat.log_start_num
jb process_i999
mov si, offset entry_text
call record_cmd ;go log request header etc.
process_i999:
ret
process_int endp
;--------------------------------------------------------------
;process_ret |
;--------------------------------------------------------------
process_ret proc near
;
;Compare location from which int was generated with the area we expected
;to generate it. If for some reason it isn't correct, simply return.
les bx, dword ptr old_stack_ptr
les di, dword ptr es:[bx].mdrv_off
mov ax, es
cmp ax, mdrv_ret_ptr.d_segment
je process_r100
jmp process_r999 ;far jump
process_r100:
sub di, 2 ;back to "int" instruction
cmp di, mdrv_ret_ptr.d_offset ;offset we are expecting?
je process_r120
jmp process_r999
process_r120:
;
;Replace the int instruction with original contents
;
call restor_instruc
;Fix value for the offset of where to return back to 2 bytes to location
;of int instruction.
les bx, dword ptr old_stack_ptr
mov es:[bx].mdrv_off, di
;
;If user has patched user int into the driver being monitored, repatch that
;location.
;
cmp patch_flag, TRUE
jne process_r500
les di, dword ptr mdrv_strat_ptr.d_offset
;
;Save code at that location and patch in int instruction.
;
call save_n_patch
process_r500:
mov drv_state, EXPECT_STRAT
;Show command block only upon entry into the monitored device driver?
cmp config_dat.show_cmd_blk, INPUT
je process_r900
mov ax, drv_req_num ;exceeded # commands to log?
cmp ax, config_dat.max_to_log
jbe process_r700
jmp process_r999 ;if yes, don't log any more
process_r700:
;
;Determine if the number of requests so far have reached the request number
;where the user wishes to start logging.
;
cmp ax, config_dat.log_start_num
jae process_r800
jmp process_r999 ;far jump
process_r800:
mov si, offset exit_text ;"Exit"
call record_cmd ;go log request header etc.
process_r900:
les bx, mdrv_req_ptr ;get ptr to request header
cmp block_dev_flag, TRUE ;is this a block device?
jne process_r950
cmp es:[bx].req_hdr_cmd, CMD_INIT
jne process_r910
lds si, es:[bx].cmd0_bpb_ptr ;get ptr to BPB table
mov si, [si] ;move from table to ptr
jmp short process_r930
process_r910:
cmp es:[bx].req_hdr_cmd, CMD_BUILD_BPB
jne process_r950
lds si, es:[bx].cmd2_bpb_ptr ;get ptr to bpb table
process_r930:
mov ax, [si] ;get sector size
mov cs:sector_size, ax ;save it
push cs
pop ds ;get local ds
process_r950:
cmp log_it, FALSE ;if command not to be logged
je process_r999
push cs
pop es ;es=seg of output buffer
cmp io_table_ptr, NULL ;is this an I/O command?
je process_r970
call show_buffer ;if so, go display data
process_r970:
;
;do command completion status stuff
push es ;save print buffer seg
les bx, mdrv_req_ptr ;ptr to request block
mov bx, es:[bx].req_hdr_status ;get cmd status
pop es
push bx ;save cmd status
mov si, offset cmd_com_text ;"Command completion "
call put_til_null
test bx, ERR_BIT ;error?
jnz process_r980 ;if so, go get error code
mov si, offset success_text
jmp short process_r990
process_r980:
and bx, 00ffh ;get return code portion only
cmp bl, MAX_ERR ;out of range of error codes?
jbe process_r985
mov si, offset err_msg16 ;unknown error code message
jmp short process_r990
process_r985:
shl bx, 1
mov si, [bx + err_msg_ptrs]
process_r990:
call put_and_skip ;print status
pop bx ;cmd status
test bx, ERR_BIT ;error?
jz process_r999 ;if no error, return
cmp config_dat.wait_key_err, TRUE ;stop on errors?
jne process_r999
mov si, offset stop_msg
call put_and_skip
call get_key
process_r999:
ret
process_ret endp
;--------------------------------------------------------------
;show_buffer - Called just after driver's interrupt routine |
; completes and it has been determined that the |
; command processed was an I/O command. |
; |
; Check user configured options for displaying |
; I/O buffers (e.g. show only reads, etc.) |
; If configured to display buffers for this |
; type of command, write the data. |
; |
; |
; Enter: ds = our local data |
; di = offset into output buffer |
; |
; Exit: di = offset of next output buffer |
; position. |
; Save ds register |
;--------------------------------------------------------------
show_buffer proc near
push ds
les bx, mdrv_req_ptr ;get pointer to cmd
cmp func_req_ptr.d_segment, NULL
je show_b100
;
;if command has a function, get ptr to it.
;
les bx, func_req_ptr ;get pointer to cmd
show_b100:
;See if block size is indicated in the command (with MSCDEX,
;cooked or raw dictates block size).
;
mov si, io_table_ptr ;get ptr to i/o info
cmp [si].io_bs_indic, TRUE
je show_b200 ;use BPB block size
;(1 byte if char)
add bx, [si].io_off_indic ;point to cmd block byte
;that tells size
add si, size io_table ;get to optional table elements
show_b150:
mov al, [si].io_bs_value ;get value that tells blk size
cmp es:[bx], al ;match with cmd req blk value?
je show_b180
cmp al, TABLE_TERM ;cmd block not right?
jne show_b170
jmp show_b999 ;far jump to exit
show_b170:
add si, size io_bs_elements ;get to next value to match
jmp short show_b150
show_b180:
mov ax, [si].io_bs
mov sector_size, ax
mov bx, mdrv_req_ptr.d_offset ;point back to start cmd blk
cmp func_req_ptr.d_segment, NULL
je show_b190
mov bx, func_req_ptr.d_offset ;point back to
;start of cmd block
show_b190:
mov si, io_table_ptr ;get ptr to i/o info
show_b200:
push bx ;save start of cmd buffer
add bx, [si].io_count
mov ax, es:[bx] ;get count
pop bx
mov sector_count, ax
add bx, [si].io_buf_ptr_off
cmp [si].io_type, INPUT ;is this input or output?
jne show_b210
cmp config_dat.show_buf_in, TRUE ;show input buffers?
jne show_b999
mov ax, config_dat.max_show_in ;get max configured to show
mov max_blocks, ax
jmp short show_b230
show_b210:
cmp config_dat.show_buf_out, TRUE ;show output buffers?
jne show_b999
mov ax, config_dat.max_show_out ;max configured to show
mov max_blocks, ax
show_b230:
mov block_count, 1 ;start counting the blocks
push es ;save segment of cmd block
push cs
pop es ;es=seg of output buffer
call skip_line
mov si, offset data_buf_text
call put_and_skip
pop es
lds si, es:[bx] ;get ptr to i/o buffer
push cs
pop es ;get es = local data
show_b240:
mov bx, cs:sector_count ;get number of chars or blocks
cmp cs:sector_size, 1 ;doing characters?
je show_b250
show_b245:
mov ax, cs:max_blocks
cmp cs:block_count, ax ;showed maximum desired?
ja show_b999
call put_out_block
mov bx, cs:sector_size
show_b250:
call dump_n_count
cmp cs:sector_size, 1 ;doing characters?
je show_b999 ;then done
call skip_line
dec cs:sector_count
jz show_b999
inc cs:block_count
jmp short show_b245
show_b999:
pop ds
ret
show_buffer endp
;--------------------------------------------------------------
;put_out_block - print "block " and block number. |
; |
; Enter: block_count contains number |
; Save ds, si registers |
;--------------------------------------------------------------
put_out_block proc near
push ds
push si
push cs
pop ds ;get ds=our local data
mov si, offset block_text
call put_til_null
mov ax, block_count
call out_int
call term_line
call out_line
call skip_line
pop si
pop ds
ret
put_out_block endp
;--------------------------------------------------------------
;restor_instruc - replace the 2 bytes of code where int |
; instruction had been patched in. |
; |
; Enter: es:di location to be patched |
;--------------------------------------------------------------
restor_instruc proc near
mov ax, save_code
mov es:[di], ax ;put it into the code
ret
restor_instruc endp
;--------------------------------------------------------------
;save_n_patch - Save the 2 bytes of code where int instruction|
; is to be placed. Place int instruction in |
; the code. |
; |
; Enter: es:di = location to be patched |
;--------------------------------------------------------------
save_n_patch proc near
mov ax, (USER_INT shl 8) or INT_OP_CODE
xchg ax, es:[di]
mov save_code, ax
ret
save_n_patch endp
;--------------------------------------------------------------
;record_cmd - Make call to do table lookup on command. Also, |
; determine if this type of command is to be |
; logged. If to be logged, write out the |
; description of the command and dump the cmd |
; request block (and any "packet" area). |
; |
; Enter: ds = our local data |
; si = offset of string indicating if |
; we are examining the cmd request |
; on "Entry" to or "Exit" from the |
; driver's interrupt routine. |
; |
; Exit: di = next offset in output buffer. |
; |
; DS register saved. |
;--------------------------------------------------------------
record_cmd proc near
les bx, mdrv_req_ptr ;ptr to request block
push si ;save ptr to "Entry" or "Exit"
call find_func
mov bx, si ;save ptr to cmd table
pop si
mov di, offset out_buf
cmp log_it, FALSE ;don't log this command?
je record_c900
push ds
pop es ;get es = local ds
call skip_line
call put_til_null ;output "Entry" or "Exit"
mov si, offset driv_req_text
call put_til_null ;output "Driver request"
mov ax, drv_req_num
call out_int ;output sequence number
mov si, bx ;si = ptr to cmd info table
call out_descrip ;output command description
;
;si contains offset of cmd info table entry
;
call prt_req ;print cmd request block
cmp byte ptr [si].ri_func_ptr, NULL ;a function?
je record_c900
call skip_line
mov bx, hold_sub_det_ptr ;get fuction table offset
mov si, [bx].fd_descrip ;function description
call put_and_skip ;go print it
mov bl, [bx].fd_packet_len ;length of function packet
sub bh, bh
push ds
lds si, func_req_ptr
call dump_n_count
call skip_line
pop ds
record_c900:
ret
record_cmd endp
;--------------------------------------------------------------
;find_func - Find the command requested in the table of |
; command information. Also, determine if |
; requested command should be logged. |
; |
; Enter: es:bx = ptr to function request |
; |
; Exit: si = offset of table entry |
;--------------------------------------------------------------
find_func proc near
mov al, es:[bx].req_hdr_cmd
;
;Search through a table of commands. Since some drivers such as those
;used with MSCDEX use nonsequential command codes, we can't simply index
;into the table.
;
mov si, offset cmd_table
find_func100:
cmp al, [si].ri_cmd_code ;found?
je find_func500
cmp byte ptr [si].ri_cmd_code, TABLE_TERM ;not found?
je find_func500
add si, size req_info ;advance to next entry
jmp short find_func100
find_func500:
mov ax, [si].ri_iotbl_ptr
mov io_table_ptr, ax ;save I/O table information
mov ax, NULL
mov func_req_ptr.d_segment, ax ;default to no function
mov func_req_ptr.d_offset, ax
cmp [si].ri_func_ptr, ax ;is there a function?
je find_func600
push si
mov si, [si].ri_func_ptr ;ptr to function table
call find_sub_func ;return bx = function
;detail info table entry
pop si
find_func600:
mov log_it, TRUE ;default to logging
cmp config_dat.log_all, TRUE
je find_func900
cmp byte ptr [si].ri_log_flag, FALSE
je find_func800
cmp [si].ri_func_ptr, NULL ;is there a function?
je find_func900
cmp byte ptr [bx].fd_log_flag, TRUE ;log this function?
je find_func900
find_func800:
mov log_it, FALSE ;don't log this command
find_func900:
ret
find_func endp
;--------------------------------------------------------------
;find_sub_func - find detailed function table entry for |
; command. |
; |
; Enter: ds:si = ptr to function table |
; es:bx = ptr to command request block |
; |
; Exit: bx = offset of detailed function |
; table entry. |
;--------------------------------------------------------------
find_sub_func proc near
push di
push es
push es
push bx ;save ptr to cmd req block
add bx, [si].f_off_ptr
les bx, es:[bx] ;get ptr to function
mov func_req_ptr.d_segment, es ;save it
mov func_req_ptr.d_offset, bx
pop bx
pop es ;restore ptr to cmd req block
cmp byte ptr [si].f_sub_in, TRUE ;is function code
;here or pointed to?
je find_sub_f100
add bx, [si].f_off_ptr
les bx, es:[bx] ;get ptr to function
find_sub_f100:
;
;es:bx holds ptr to start of command block (or subcommand block). Determine
;where major code and minor code (if any) are found within cmd block.
;
mov di, [si].f_off_cat_code
mov al, es:[bx + di] ;get major code
mov ah, NULL ;default to no minor code
cmp [si].f_off_fun_code, NULL ;no minor code?
je find_sub_f200
mov di, [si].f_off_fun_code
mov ah, es:[bx + di] ;get minor code
find_sub_f200:
mov bx, offset [si].f_detail_ptr ;get ptr to detailed info
find_sub_f300:
cmp ax, word ptr [bx].fd_cat_code ;codes found in table?
je find_sub_f600
find_sub_f500:
cmp byte ptr [bx].fd_cat_code, TABLE_TERM ;not found?
je find_sub_f600
add bx, size func_detail ;advance to next entry
jmp short find_sub_f300
find_sub_f600:
mov ax, [bx].fd_iotbl_ptr
mov io_table_ptr, ax ;save io table information
mov hold_sub_det_ptr, bx
pop es
pop di
ret
find_sub_func endp
;--------------------------------------------------------------
; out_int - format a nonzero binary number to ASCII and |
; place formatted number into output buffer. |
; |
; Enter: ax = binary number. |
; es:di = ptr to output buffer. |
; |
; Exit: di = next offset in output buffer. |
;--------------------------------------------------------------
out_int proc near
push bx
push cx
push si
add di, 4
mov si, di ;advance to last digit
mov cx, 5 ;5 digits
mov bx, 10 ;divide by 10
out_i100:
xor dx, dx
div bx
add dl, '0' ;make ASCII
or ax, ax
jnz out_i200
cmp dl, '0'
jne out_i200
mov dl, ' ' ;no leading zeros
out_i200:
mov es:[si], dl ;get remainder
dec si
loop out_i100
add di, 8 ;need some space after number
pop si
pop cx
pop bx
ret
out_int endp
out_descrip proc near
push si
mov si, [si].ri_descrip ;get ptr to cmd description
call put_and_skip ;print it
pop si
ret
out_descrip endp
get_key proc near
sub ah, ah
int 16h
ret
get_key endp
;--------------------------------------------------------------
;prt_log_hdr - print the device name, type, and load address |
; to the configured output device. |
; |
; Enter: es = segment where driver is loaded. |
; ds = our local data. |
; |
; Exit: di = next offset in output buffer. |
;--------------------------------------------------------------
prt_log_hdr proc near
mov bx, offset block_text
mov block_dev_flag, TRUE
push es
pop ds ;get ds=monitored driver's segment
push cs
pop es ;get es=local segment
xor si, si
test byte ptr [si].dev_attrib.w_msb, 80h ;char device?
jz prt_log_h200
mov di, offset es:head_drv_name
mov cx, HEAD_DRV_NLEN
mov si, size dev_header ;point to device name
rep movsb ;move into buffer
mov bx, offset es:char_text
mov es:block_dev_flag, FALSE ;flag as a char device
prt_log_h200:
mov si, bx ;offset of device description
push ds ;save monitored driver's segment
push es
pop ds ;ds = local data
mov di, offset head_dev_type
call put_til_null ;output heading line
mov di, offset head_load
pop ds ;restore driver segment
xor si, si
call format_seg
push es
pop ds
mov di, offset out_buf
push di
mov si, offset head_line
call put_til_null ;move heading into buffer
call term_line
pop di
call out_line
ret
prt_log_hdr endp
prt_req proc near
push ds
push si
lds si, mdrv_req_ptr
sub bh, bh
mov bl, [si] ;get number of bytes
call dump_n_count
pop si
pop ds
ret
prt_req endp
;--------------------------------------------------------------
;dump_n_count - do a dump of specified area. |
; |
; Enter: ds:si = ptr to area. |
; bx = number of bytes. |
; Exit: di = start of output buffer |
;--------------------------------------------------------------
dump_n_count proc near
call dump_a_line
call out_line
cmp bx, 10h
jbe dump_n_c200
sub bx, 10h
jmp short dump_n_count
dump_n_c200:
ret
dump_n_count endp
;--------------------------------------------------------------
;dump_a_line - given a ptr ds:si to a buffer, form 10h bytes |
; of dump data at es:di. |
;--------------------------------------------------------------
dump_a_line proc near
push di ;save start print buf
call format_seg
add di,2 ;leave some space
mov cx, 10h
push ds
push si ;save start of data
dump_a_l100:
lodsb
cmp si, 0 ;did offset just wrap?
jne dump_a_l150
mov ax, ds ;if so, get to new
add ax, 1000h ;64k
mov ds, ax
dump_a_l150:
call put_hex_dig
cmp cl, 9
jne dump_a_l200
mov al, '-'
mov es:[di],al
dump_a_l200:
inc di
loop dump_a_l100
pop si
pop ds
add di, 3
mov cx, 10h
dump_a_l250:
lodsb
cmp si, 0 ;did offset just wrap?
jne dump_a_l260
mov ax, ds ;if so, get to new
add ax, 1000h ;64k
mov ds, ax
dump_a_l260:
cmp al, ' '
jae dump_a_l300
mov al, '.'
dump_a_l300:
stosb
loop dump_a_l250
call term_line
pop di
ret
dump_a_line endp
clear_line proc near
push di
mov cx, 40
mov ax, ' '
rep stosw
pop di
ret
clear_line endp
;--------------------------------------------------------------
;format_seg - format segment and offset in ds:si in ASCII |
; as follows: |
; xxxx:xxxx |
; Put into buffer from ptr es:di |
; |
; Exit: di = next offset in output buffer. |
;--------------------------------------------------------------
format_seg proc near
mov ax, ds ;do the segment
mov cx, 2 ;2 words
format_s100:
xchg al, ah ;want to print MSB first
mov dl, ah ;save LSB
call put_hex_dig
mov al, dl
call put_hex_dig
mov al, ':'
stosb
mov ax, si ;do the offset
loop format_s100
mov byte ptr es:[di - 1], ' ' ;ignore last ':'
ret
format_seg endp
;--------------------------------------------------------------
;out_line - print line at cs:out_buf. Reset di to beginning. |
; |
;--------------------------------------------------------------
out_line proc proc
push bx
push si
push ds
push cs
pop ds ;get ds = cs
mov di, offset out_buf
mov si, di
mov bx, config_dat.output_device
shl bx, 1 ;get command code
call word ptr [bx + out_table]
call clear_line
pop ds
pop si
pop bx
ret
out_line endp
prt_to_null proc near
ret
prt_to_null endp
prt_to_screen proc near
mov ah, 14 ;teletype
mov bl, 0fh ;intense white
lodsb
or al, al ;end of data?
jz ptr_to_sc900
int 10h
jmp short prt_to_screen
ptr_to_sc900:
ret
prt_to_screen endp
prt_to_printer proc near
mov dx, LPT1
ptr_to_pr100:
mov ah, 0 ;print char
lodsb
or al, al ;end of data?
jz ptr_to_pr900
int 17h
jmp short ptr_to_pr100
ptr_to_pr900:
ret
prt_to_printer endp
prt_to_mem proc near
push di ;save buffer ptr
push es
les di, user_data_ptr ;get user's buf ptr
mov ax, es
cmp ax, NULL ;has user made IOCTL yet?
je prt_to_mi900 ;if not, can't write
les di, wrk_data_ptr ;get working ptr
;
;Has user reset the buffer count? If so, set work pointer to start of
;user buffer.
cmp wrk_data_count.d_segment, 0
ja prt_to_mi100
cmp wrk_data_count.d_offset, 0
ja prt_to_mi100
les di, user_data_ptr
mov wrk_data_ptr.d_offset, di
mov wrk_data_ptr.d_segment, es
prt_to_mi100:
mov dx, user_data_size.d_segment ;is user buffer full?
cmp dx, wrk_data_count.d_segment
ja prt_to_mi120
mov dx, user_data_size.d_offset
cmp dx, wrk_data_count.d_offset
ja prt_to_mi120
jmp short prt_to_mi900 ;if so, can't write
prt_to_mi120:
movsb
cmp di, 0 ;did we just wrap?
jne prt_to_mi150
mov ax, es ;if so, get to new
add ax, 1000h ;64k
mov es, ax
prt_to_mi150:
inc wrk_data_count.d_offset
jnz prt_to_mi200
inc wrk_data_count.d_segment
prt_to_mi200:
cmp byte ptr [si], NULL ;end of line?
jne prt_to_mi100 ;if not, continue
prt_to_mi900:
mov wrk_data_ptr.d_offset, di ;save where left off
mov wrk_data_ptr.d_segment, es
pop es
pop di
ret
prt_to_mem endp
skip_line proc near
mov word ptr cs:[di], (CR SHL 8) OR LF
add di, 2
ret
skip_line endp
term_line proc near
call skip_line
mov byte ptr cs:[di], NULL
inc di
ret
term_line endp
put_til_null proc near
lodsb
or al, al
jz put_til_900
stosb
jmp short put_til_null
put_til_900:
ret
put_til_null endp
put_and_skip proc near
call put_til_null ;put it in buffer
call term_line
call out_line ;print it
call skip_line
ret
put_and_skip endp
put_hex_dig proc near
push cx
mov cx, 2 ;2 digits in al
mov ah, al
put_hex_100:
shr al, 1
shr al, 1
shr al, 1
shr al, 1
cmp al, 9
ja put_hex_500
add al, '0'
jmp short put_hex_900
put_hex_500:
add al, 'A' - 10
put_hex_900:
stosb
mov al, ah
shl al, 1
shl al, 1
shl al, 1
shl al, 1
loop put_hex_100
pop cx
ret
put_hex_dig endp
out_buf db 256 dup(' ')
end_out_buf EQU $ - out_buf
code ends
end